package com.linxuan.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.linxuan.reggie.common.R;
import com.linxuan.reggie.dto.DishDto;
import com.linxuan.reggie.entity.Category;
import com.linxuan.reggie.entity.Dish;
import com.linxuan.reggie.service.CategoryService;
import com.linxuan.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {

    @Autowired
    private DishService dishService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增POST、修改PUT。POST方式参数在方法体里面以JSON格式存储
     *
     * @param dishDto 用RequestBody封装参数放到DishDto里面
     * @return 新增菜品成功
     */
    @PostMapping
    public R<String> save(@RequestBody DishDto dishDto) {
        dishService.saveWithFlavor(dishDto);
        return R.success("新增菜品成功");
    }

    /**
     * 前端发送查询请求，查询菜品信息，有两种可能：分页查询、指定名称查询
     * 首先查询出来dish表的菜品信息，根据dish表菜品信息的ID查询dish_flavor信息，然后两个合并放到DishDto类里面
     *
     * @param page     页数
     * @param pageSize 每页数量
     * @param name     根据名称查询菜品信息
     * @return 分页查询结果
     */
    @GetMapping("/page")
    public R<Page<DishDto>> page(int page, int pageSize, String name) {
        // 构造分页查询构造器
        Page<Dish> pageInfo = new Page<>(page, pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        // 构造条件构造器
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 如果name不为空，那么就对其模糊查询
        lambdaQueryWrapper.like(!StringUtils.isEmpty(name), Dish::getName, name);

        // 分页查询
        dishService.page(pageInfo, lambdaQueryWrapper);

        // 对象拷贝并忽略records属性。
        BeanUtils.copyProperties(pageInfo, dishDtoPage, "records");

        // 获取所有的分页查询结果。
        List<Dish> records = pageInfo.getRecords();
        // 使用Stream流进行处理，map映射，将一种数据映射为另一种类型数据
        List<DishDto> list = records.stream().map((item) -> {
            DishDto dishDto = new DishDto();

            // 将item所有属性赋值给dishDto
            BeanUtils.copyProperties(item, dishDto);
            // 根据id查分类对象
            Category category = categoryService.getById(item.getCategoryId());
            if (category != null) {
                dishDto.setCategoryName(category.getName());
            }
            return dishDto;
        }).collect(Collectors.toList());

        dishDtoPage.setRecords(list);
        return R.success(dishDtoPage);
    }


    /**
     * 根据Id查询菜品信息与对应的口味信息
     *
     * @param id ID
     * @return 菜品以及口味信息
     */
    @GetMapping("/{id}")
    public R<DishDto> getById(@PathVariable("id") Long id) {
        return R.success(dishService.getByIdWithFlavor(id));
    }

    /**
     * 修改操作
     *
     * @param dishDto 前端传回来的DishDto数据
     * @return 返回修改成功
     */
    @PutMapping()
    public R<String> update(@RequestBody DishDto dishDto) {
        dishService.updateWithFlavor(dishDto);
        return R.success("修改成功");
    }

    /**
     * 删除菜品操作
     *
     * @param ids ids
     * @return 删除成功
     */
    @DeleteMapping
    public R<String> delete(String[] ids) {
        dishService.deleteWithFlavorAndImg(ids);
        return R.success("删除成功");
    }

    /**
     * 批量进行起售或者停售
     *
     * @param status 0停售 1起售，发送过来的值代表将要操作
     * @param ids    需要操作的菜品id列表
     * @return 操作是否成功
     */
    @PostMapping("/status/{status}")
    public R<String> sale(@PathVariable("status") int status, String[] ids) {
        for (String id : ids) {
            // 获取该ID所对应的菜品信息
            Dish dish = dishService.getById(id);
            // 设置状态
            dish.setStatus(status);
            // 修改菜品信息
            dishService.updateById(dish);
        }
        return R.success("修改成功");
    }

    /**
     * 通过菜品分类查询该类菜品列表
     *
     * @param dish 前端参数为categoryId菜品分类ID，后端使用Dish接收复用性提高了
     * @return 我们需要返回前端关于菜品信息
     */
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish) {
        // 获取到前端传过来的分类ID
        Long categoryId = dish.getCategoryId();
        // 返回结果，这里只是声明一下
        List<DishDto> dishDtoList;

        // 动态构造redis数据库的键
        String key = "dish_" + categoryId;
        dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);
        // 查询Redis有结果那么直接返回
        if (dishDtoList != null) {
            log.info("查询到Redis有着" + categoryId + "菜品分类ID的结果，所以这里直接返回");
            return R.success(dishDtoList);
        }

        // 查询MySQL数据库
        dishDtoList = dishService.getDishDtoListByCategoryId(categoryId);
        if (dishDtoList != null) {
            // 如果查询数据库有结果那么就存储至Redis中，设置过期时间为60分钟
            redisTemplate.opsForValue().set(key, dishDtoList, 60, TimeUnit.MINUTES);
            return R.success(dishDtoList);
        }
        return R.error("查询失败！");
    }
}
